import type { AxiosResponse } from 'axios';
import type { RequestOption } from '@sa/axios';
import { BACKEND_ERROR_CODE, createFlatRequest } from '@sa/axios';
import { useAuthStore } from '@/store/modules/auth';
import { getServiceBaseURL } from '@/utils/service';
import { $t } from '@/locales';
import { getAuthorization, handleExpiredRequest, showErrorMsg } from './shared';
import type { RequestInstanceState } from './type';

const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);

function getFlatRequest(options: Partial<RequestOption<App.Service.Response>> = {}) {
  const request = createFlatRequest<App.Service.Response, RequestInstanceState>(
    {
      baseURL,
      headers: {
        apifoxToken: 'FY65Vng88xra_BveQ5E_4'
      }
    },
    {
      async onRequest(config) {
        const Authorization = getAuthorization();
        Object.assign(config.headers, { Authorization });

        return config;
      },
      onTokenRefresh(newToken) {
        // 无感知token刷新：自动更新本地存储的token
        const authStore = useAuthStore();
        authStore.setToken(newToken);
        console.log('🔄 Token automatically refreshed');
      },
      isBackendSuccess(response) {
        // when the backend response code is "0000"(default), it means the request is success
        // to change this logic by yourself, you can modify the `VITE_SERVICE_SUCCESS_CODE` in `.env` file
        return String(response.data.code) === import.meta.env.VITE_SERVICE_SUCCESS_CODE;
      },
      async onBackendFail(response, instance) {
        console.log('%c [ 👉 onBackendFail 👈 ]-35', 'font-size:16px; background:#3cd735; color:#80ff79;', response);
        const authStore = useAuthStore();
        const responseCode = String(response.data.code);

        function handleLogout() {
          authStore.resetStore();
        }

        function logoutAndCleanup() {
          handleLogout();
          window.removeEventListener('beforeunload', handleLogout);

          request.state.errMsgStack = request.state.errMsgStack.filter(msg => msg !== response.data.message);
        }

        // when the backend response code is in `logoutCodes`, it means the user will be logged out and redirected to login page
        const logoutCodes = import.meta.env.VITE_SERVICE_LOGOUT_CODES?.split(',') || [];
        if (logoutCodes.includes(responseCode)) {
          handleLogout();
          return null;
        }

        // when the backend response code is in `modalLogoutCodes`, it means the user will be logged out by displaying a modal
        const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
        if (modalLogoutCodes.includes(responseCode) && !request.state.errMsgStack?.includes(response.data.message)) {
          request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.message];

          // prevent the user from refreshing the page
          window.addEventListener('beforeunload', handleLogout);

          window.$dialog?.error({
            title: $t('common.error'),
            content: response.data.message,
            positiveText: $t('common.confirm'),
            maskClosable: false,
            closeOnEsc: false,
            onPositiveClick() {
              logoutAndCleanup();
            },
            onClose() {
              logoutAndCleanup();
            }
          });

          return null;
        }

        // when the backend response code is in `expiredTokenCodes`, it means the token is expired, and refresh token
        // the api `refreshToken` can not return error code in `expiredTokenCodes`, otherwise it will be a dead loop, should return `logoutCodes` or `modalLogoutCodes`
        const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
        if (expiredTokenCodes.includes(responseCode)) {
          const success = await handleExpiredRequest(request.state);
          if (success) {
            const Authorization = getAuthorization();
            Object.assign(response.config.headers, { Authorization });

            return instance.request(response.config) as Promise<AxiosResponse>;
          }
        }

        return null;
      },
      transformBackendResponse(response) {
        return response.data.data;
      },
      onError(error) {
        // when the request is fail, you can show error message

        if (error.code === 'ERR_CANCELED') return;

        // handle 403 Forbidden error - user needs to login
        if (error.response?.status === 403) {
          const authStore = useAuthStore();
          authStore.resetStore();
          return;
        }

        let message = error.message;
        let backendErrorCode = '';

        // get backend error message and code
        if (error.code && BACKEND_ERROR_CODE.split(',').includes(error.code)) {
          message = error.response?.data?.message || message;
          backendErrorCode = String(error.response?.data?.code || '');
        }

        // the error message is displayed in the modal
        const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
        if (modalLogoutCodes.includes(backendErrorCode)) {
          return;
        }

        // when the token is expired, refresh token and retry request, so no need to show error message
        const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
        if (expiredTokenCodes.includes(backendErrorCode)) {
          return;
        }

        showErrorMsg(request.state, message);
      },
      ...options
    }
  );

  return request;
}

export const request = getFlatRequest();

// 某些接口不是分页接口，但是需要当作套用分页的页面，故需要对数据结构做转换
export const fakePaginationRequest = getFlatRequest({
  transformBackendResponse(response) {
    return { data: response.data.data };
  }
});
